<?php

namespace App\Services\Product;

use App\Exceptions\ChargeRecordException;
use App\Exceptions\DeviceException;
use App\Exceptions\UserException;
use App\Facades\ChargeRecordManager;
use App\Facades\DeviceManager;
use App\Facades\UserManager;
use App\Jobs\CommandRepeater;
use App\Models\ChargeRecord;
use Cache;
use Carbon\Carbon;
use ChengFang\EasyPay\PaymentContext;
use DB;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Request;

class ChargeRecordService {
    use \ChengFang\EasyPay\Traits\WechatPayNotify, DispatchesJobs;

    /**
     * 充值，微信公众号内支付
     * @param  int  $money  金额
     * @return [type] 
     */
    public function wechatUnifiedPay($flow, $money){
        $userInfo = UserManager::getUser()->userInfo;
        $deviceState = $this->getCacheDeviceState($userInfo->current_device_id);

        $goldAmount = round($money);
        $orderNumber = date('YmdHis').substr(microtime(), 2, 4);
        $chargeRecord = ChargeRecordManager::createOrder([
            'order_number' => $orderNumber,
            'user_id' => $userInfo->user_id,
            'open_id' => $userInfo->open_id,
            'device_id' => $userInfo->current_device_id,
            'money' => number_format($money, 2, '.', ''),
            "residual_flow" => $deviceState['residualFlow'] + $flow,
            'flow' => $flow,
        ]);

        $order = [
            'body' => $flow.'升',
            'detail' => $flow.'升',
            'out_trade_no' => $orderNumber,
            'total_fee' => round($money) * 100,
            'spbill_create_ip' => Request::ip(),
            'notify_url' => url('/api/wechat-pay-notify'),
            'openid' => $userInfo->open_id,
        ];
        
        $context = new PaymentContext('Strategy\WechatPay\WechatJsPay');
        $context->execute($order);
        // info($context->getResult()->createWebPaymentPackage());
        return $context->getResult()->createWebPaymentPackage();
        
    }

    /**
     * 充值，微信扫码支付
     * @param  integer $money
     * @return [type]
     */
    public function wechatJsPay($flow, $money){
        $userInfo = UserManager::getUser()->userInfo;
        $deviceState = $this->getCacheDeviceState($userInfo->current_device_id);

        $goldAmount = round($money);
        $orderNumber = date('YmdHis').substr(microtime(), 2, 4);
        $chargeRecord = ChargeRecordManager::createOrder([
            'order_number' => $orderNumber,
            'user_id' => $userInfo->user_id,
            'open_id' => $userInfo->open_id,
            'device_id' => $userInfo->current_device_id,
            'money' => number_format($money, 2, '.', ''),
            "residual_flow" => $deviceState['residualFlow'] + $flow,
            'flow' => $flow,
        ]);

        $order = [
            'body' => $flow.'升',
            'detail' => $flow.'升',
            'out_trade_no' => $orderNumber,
            'total_fee' => 1,//round($money) * 100,
            'product_id' => $orderNumber,
            'spbill_create_ip' => Request::ip(),
            'notify_url' => url('/api/wechat-pay-notify'),
        ];

        $context = new PaymentContext('Strategy\WechatPay\WechatUnifiedPay');
        $context->execute($order);

        return $context->getResult()->getCodeUrl();
    }

    /**
     * 充值，微信回调，增加用户升数量
     * @param  [type] $body 
     * @return [type]       
     */
    public function recharge($body){
        try{
            $context = new PaymentContext('Strategy\WechatPay\WechatPayNotify');
            $context->execute($body);
            $response = $context->getResult();
            $orderNumber = $response->getOutTradeNo();

            $chargeRecord = ChargeRecordManager::findByOrderNumber($orderNumber);

            if($chargeRecord->status == ChargeRecord::ORDER_STATUS_PAID){
                return $this->success();
            }

            DB::transaction(function() use ($chargeRecord) {
                $chargeRecord->update(['status' => ChargeRecord::ORDER_STATUS_PAID]);
                $job = (new CommandRepeater('recharge', $chargeRecord->flow, $chargeRecord->device->code, $chargeRecord->id, $chargeRecord->user_id))->onQueue('commandRepeater');
                $this->dispatch($job);
            });
            return $this->success();
        }catch(Exception $e){
            info(['ChargeRecordService.recharge' => $body]);
            return $this->fail();
        }
    }

    /**
     * 获取金额和金币数量数组
     * @return [type] 
     */
    public function getCharge(){
        $charges = config('heting.rechargeScale');
        if(!count($charges)){
            throw new ChargeRecordException('notFound');
        }
        return $charges;
    }

    /**
     * 添加充值记录
     * @param integer $flow     
     * @param integer $deviceId 
     * @param string $remark
     */
    public function add($flow, $deviceId, $remark)
    {
        $user = UserManager::getUser();
        if(!$user->hasAccess(['finance'])){
            throw new UserException('auth');
        }
        if($user->is_admin){
            $deviceState = $this->getCacheDeviceState($deviceId);
            $chargeRecord = ChargeRecordManager::createOrder([
                'order_number' => date('YmdHis').substr(microtime(), 2, 4),
                'admin_id' => $user->id,
                'device_id' => $deviceId,
                'flow' => $flow,
                "residual_flow" => $deviceState['residualFlow'] + $flow,
                'status' => 1,
                'remark' => $remark,
            ]);
            return $chargeRecord;
        }
        
    }

    /**
     * 获取充值记录列表
     * @param  string $condition 
     * @return              
     */
    public function findChargeList($condition)
    {
        $chargeRecords = ChargeRecordManager::findChargeListByQuery($condition);
        return $chargeRecords->with(['device' => function($query){
            $query->with(['installInfo' => function($query){
                $query->select('device_code', 'customer_name');
            }])->select('id', 'code');
        }, 'userInfo' => function($query){
            $query->select('user_id', 'name');
        }, 'adminInfo' => function($query){
            $query->select('user_id', 'name');
        }, 'dischargeAdmin' => function($query){
            $query->select('user_id', 'name');
        }])->paginate(15);
    }

    /**
     * 根据设备 id 获取设备缓存数据
     * @param  integer  $deviceId 
     * @return            
     */
    public function getCacheDeviceState($deviceId)
    {
        $device = DeviceManager::getDeviceByQuery('id', $deviceId);
        $deviceState = Cache::get($device->code.'state');
        if(is_null($deviceState)){
            throw new DeviceException('notConnect');
        }
        return $deviceState;
    }

    /**
     * 根据设备 id 获取设备列表
     * @param  integer  $deviceId   
     * @param  integer  $userId     
     * @param  boolean $isPaginate 
     * @return               
     */
    public function getChargeListByDeviceId($deviceId = null, $userId = null, $isPaginate = true)
    {
        $chargeRecords = ChargeRecordManager::getChargeListByQueryColumn('device_id', $deviceId)->where('status', '>', 1);
        $query = $chargeRecords->with(['device' => function($query){
            $query->with(['installInfo' => function($query){
                $query->select('device_code', 'customer_name');
            }])->select('id', 'code');
        }, 'userInfo' => function($query){
            $query->select('user_id', 'name', 'phone');
        }, 'adminInfo' => function($query){
            $query->select('user_id', 'name');
        }, 'dischargeAdmin' => function($query){
            $query->select('user_id', 'name');
        }])->latest();
        if($isPaginate){
            return $query->paginate(15);
        }else{
            return $query->select([
                'discharge_flow',
                'flow',
                'money',
                'status',
                'status_description',
                'created_at',
                ])->get();
        }
    }

    public function updateChargeRecord($chargeRecordId, $data)
    {
        $chargeRecord = ChargeRecordManager::getChageRecordById($chargeRecordId);
        if($data['discharge_flow'] > $chargeRecord->flow){
            throw new ChargeRecordException('reduceFlow');
        }
        if($chargeRecord->status == ChargeRecord::ORDER_STATUS_DISCHARGED){
            throw new ChargeRecordException('discharged');
        }
        $chargeRecord->update($data);
        return $chargeRecord;
    }

    public function getChargeListByDateAndDealer($afterDate, $beforeDate, $dealer, $isPaginate = true)
    {
        $chargeRecordBuilder = ChargeRecordManager::getChargeBuilderOrderByCreatedAt();
        if(!empty($afterDate)){
            $beforeDate = Carbon::createFromFormat('Y-m-d H:i:s', $beforeDate.' 23:59:59');
            $afterDate = Carbon::createFromFormat('Y-m-d H:i:s', $afterDate.' 00:00:00');
            if($beforeDate->lt($afterDate)){
                throw new ChargeRecordException('date');
            }
            $chargeRecordBuilder->where('created_at', '>=', $afterDate)->where('created_at', '<=', $beforeDate);
        }
        if(!empty($dealer)){
            $installInfoBuilder = DeviceManager::getInstallInfoListBuilderOrderByCreatedAt();
            $installs = $installInfoBuilder->where('dealer', 'like', '%'.$dealer.'%')->select('device_code')->get();
            $deviceIds = DeviceManager::getDevicesByDeviceCodeArray($installs->pluck('device_code'));
            $chargeRecordBuilder->whereIn('device_id', $deviceIds->pluck('id'))->with(['device' => function($query){
                $query->with(['installInfo' => function($query){
                    $query->select('device_code', 'dealer', 'customer_name');
                }])->select('id', 'code');
            }, 'userInfo' => function($query){
                $query->select('user_id', 'name');
            }, 'adminInfo' => function($query){
                $query->select('user_id', 'name');
            }, 'dischargeAdmin' => function($query){
                $query->select('user_id', 'name');
            }]);
        }
        if($isPaginate){
            return $chargeRecordBuilder->where('status', '>', 1)->paginate(15);
        }else{
            return $chargeRecordBuilder->where('status', '>', 1)->get();
        }
    }

}
